home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / ingres04.lzh / source / iutil / initucode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-18  |  14.9 KB  |  660 lines

  1. # include    <stdio.h>
  2. # include    <stdlib.h>
  3. # include    <ingres.h>
  4. # include    <aux.h>
  5. # include    <version.h>
  6. # include    <opsys.h>
  7. # include    <access.h>
  8. # include    <lock.h>
  9. # include    <signal.h>
  10. # include    <setjmp.h>
  11. # include    <pwd.h>
  12.  
  13. /*
  14. **  INITUCODE -- initialize standalone process
  15. **
  16. **    This function initializes a standalone process, initializing
  17. **    a lot of global variables, scanning the argument vector for
  18. **    some special flags (-u and +-w), seperating flags and
  19. **    parameters, and so forth.
  20. **
  21. **    Every standalone program should begin with the lines:
  22. **            i = initucode(argc, argv, ...);
  23. **            switch (i)
  24. **                ...
  25. **
  26. **    On a return of 2, 3, or 4, essentially none of the processing
  27. **    is done (particularly true with return 4).  Virtually nothing
  28. **    can be done in the calling program except print a "usage"
  29. **    message and exit.  The exception to this is that 'Pathname'
  30. **    is set, so that it can be used in the error printing.  For
  31. **    example, ingres.c cats file .../files/usage on this sort of
  32. **    error.
  33. **
  34. **    If it is preferable to not lock the database at this time,
  35. **    the 'waitmode' parameter should be passed as -1.  This still
  36. **    causes the 'Wait_action' variable to be initialized, but the
  37. **    database is not actually locked.  It can be locked by calling:
  38. **        db_lock(Dbpath, M_EXCL);
  39. **    at the proper time.
  40. **
  41. **    For the main effects of this routine, see the "Side Effects"
  42. **    section below.
  43. **
  44. **    Parameters:
  45. **        argc -- argc from main.
  46. **        argv -- argv from main.
  47. **        dbflag -- TRUE -- take the first parameter as the
  48. **                database name.
  49. **            FALSE -- don't take the first parameter as
  50. **                the database name.
  51. **        paramlist -- a pointer to an array[4] of pointers
  52. **            to character; set to the extra fields of
  53. **            the users file entry for the real user
  54. **            executing the code (not the user on the
  55. **            -u flag).  If NULL, this is ignored.
  56. **        waitmode -- M_EXCL -- set an exclusive lock on the
  57. **                database.
  58. **            M_SHARE -- set a shared lock on the database.
  59. **            -1 -- don't set a lock on the database.
  60. **                However, other stuff (Wait_action) is
  61. **                still set up so that the lock can be
  62. **                placed later by calling 'db_lock'.
  63. **
  64. **    Returns:
  65. **        0 -- everything is ok.
  66. **        1(NODB) -- the database does not exist.
  67. **        2(NOACCESS)-- you are not authorized to access this database.
  68. **        3(INVALIDUSR)-- you are not a valid INGRES user.
  69. **        4(NODBNAME)-- no database name was specified (only if dbflag
  70. **            == TRUE).
  71. **        5(INDIRECT)-- everything is ok, but there was an indirect
  72. **            taken.
  73. **        6(INDNODB)-- there was an indirect taken, but there was no
  74. **            database there.
  75. **
  76. **        If dbflag == FALSE, you can only get returns 0 and
  77. **            3.
  78. **
  79. **    Side Effects:
  80. **        A lot of variables are set, as follows:
  81. **
  82. **        Dbpath -- set to the pathname of the database (only
  83. **            if dbflag == TRUE).  It is set even if the
  84. **            database does not exist.
  85. **        Parmvect -- set to the parameters from argv, that is,
  86. **            anything not beginning with '+' or '-'.
  87. **        Flagvect -- set to the flags from argv, that is,
  88. **            everything beginning with '+' or '-'.  The
  89. **            flags '+w', '-w', and '-u' are stripped out,
  90. **            however.
  91. **        Wait_action -- set to the appropriate action (A_SLP
  92. **            or A_RTN) based on the +-w flags and whether
  93. **            we are running in background or not.
  94. **            This is automatically used by 'db_lock()'.
  95. **        Usercode -- set to the persons effective user code
  96. **            (that is, after the -u processing).  Only
  97. **            the INGRES user or the DBA can use the -u
  98. **            flag.
  99. **        Pathname -- set to the pathname of the INGRES subtree.
  100. **        Status -- an integer set to the user status field
  101. **            of the users file for the real user.
  102. **        Ing_uid -- set to the user id of the INGRES user.
  103. **
  104. **        The rubout signal (signal 2) is caught, and refered
  105. **        to the standard rubout processor (see rub.c); thus,
  106. **        a routine called 'rubproc' must be defined in the
  107. **        standalone code (which will just call exit, in the
  108. **        normal case).
  109. **
  110. **        The 'adminhdr' part of the 'Admin' struct is filled
  111. **        in.  This is not done with readadmin() and is not
  112. **        equivalent to an 'admininit()', but it does make
  113. **        the DBA and database status available.
  114. **
  115. **        This routine can also exit immediately with an
  116. **        error message.
  117. **
  118. **    Defined Constants:
  119. **        MAXPARGS -- the maximum number of parameter type
  120. **            arguments to any standalone program.
  121. **        MAXFARGS -- the maximum number of flag type arg-
  122. **            uments to any standalong program (not inclu-
  123. **            ding flags in the users file, and the +-w
  124. **            and -u flags).
  125. **
  126. **    Files:
  127. **        /etc/passwd -- to get the pathname for user "ingres".
  128. **        .../files/users -- to get all the per-user information,
  129. **            and to process the -u flag.
  130. **
  131. **    Trace Flags:
  132. **        none
  133. */
  134.  
  135.  
  136. # define    MAXFARGS    15    /* maximum flag-type arguments */
  137. # define    MAXPARGS    20    /* maximum parameter-type args */
  138.  
  139. char    *Usercode;    /* the usercode of the effective user */
  140. char    *Pathname;    /* path of INGRES subtree */
  141. int    Status;        /* the user status of the real user */
  142. int    Rubignored;    /* set if rubouts ignored */
  143.             /* (also in initproc for system processes) */
  144. int    Wait_action;    /* the action on the db_lock */
  145. char    *Dbpath;    /* the pathname of the database */
  146. char    *Flagvect[MAXFARGS+1];    /* the flags from argv */
  147. char    *Parmvect[MAXPARGS+1];    /* the parameters from argv */
  148. int    Ing_uid;    /* the user id of the INGRES user */
  149. jmp_buf    Initbuf;    /* Buffer to go back to initucode with */
  150.  
  151. extern char *ztack();
  152.  
  153. initucode(argc, argv, dbflag, paramlist, waitmode)
  154. int    argc;
  155. char    **argv;
  156. int    dbflag;
  157. char    *paramlist[4];
  158. int    waitmode;
  159. {
  160.     register char    *p;
  161.     char        *q;
  162.     char        c;
  163.     FILE        *iop;
  164.     static char    sbuf[MAXLINE * 2];
  165.     register char    *sbufp;
  166.     char        buf[MAXLINE+1];
  167.     register int    i;
  168.     int        npermit;
  169.     int        rtval;
  170.     char        *field[UF_NFIELDS];
  171.     int        actualuid;
  172.     auto int    uid;
  173.     auto int    gid;
  174.     int        waitflag;
  175.     char        *userflag;
  176.     int        fvi, pvi;
  177.     char        **avp;
  178.     char        usr_ovrd[3];
  179.     extern    void    rubcatch();
  180.     static short    tvect[100];
  181.     bool        nobuffer;
  182.     struct    passwd    *pwd;
  183.     struct    passwd    *getpwnam();
  184.  
  185.     /*
  186.     **  Set up interrupts.
  187.     */
  188.  
  189.     if ( setjmp(Initbuf) )
  190.         exit(-1);
  191.     if (signal(SIGINT, SIG_IGN) == SIG_DFL)
  192.         signal(SIGINT, rubcatch);
  193.  
  194.     /*
  195.     **  Do basic initialization, such as setting trace flags.
  196.     */
  197.  
  198.     nobuffer = tTrace(argv, 'T', tvect, 100);
  199.     if (!nobuffer)
  200.         set_so_buf();
  201.     sbufp = sbuf;
  202.  
  203.     /*
  204.     **  Get pathname of INGRES subtree from /etc/passwd file
  205.     **  entry for USERINGRES (presumably "ingres") and save it
  206.     **  in 'Pathname'.
  207.     **
  208.     **  This algorithm suggested by Jim Popa.
  209.     */
  210.  
  211.     if ( (pwd = getpwnam(USERINGRES)) == NULL )
  212.         syserr("initucode: No user %s in password file",USERINGRES);
  213.     Pathname = getenv("INGPATH");
  214.     if (Pathname == NULL)
  215.     {
  216.         Pathname = sbufp;
  217.         sbufp += smove(pwd->pw_dir, sbufp) + 1;
  218. # ifdef PATHEXT
  219.         sbufp += smove(PATHEXT, sbufp - 1);
  220. # endif PATHEXT
  221.     }
  222.  
  223.     /* create the INGRES user id */
  224.     Ing_uid = pwd->pw_uid;
  225.     endpwent();
  226.  
  227.     /*
  228.     **  Scan the argument vector.  The following flags are pulled
  229.     **  out of the vector (and argc and argv are adjusted so it
  230.     **  looks like they never existed):
  231.     **    +w, -w -- (don't) wait for the database to be free.
  232.     **    -uxxx -- run as user xxx.  If first character is a
  233.     **    colon, the format must be '-u:xx' where 'xx' is the
  234.     **    internal user code.
  235.     */
  236.  
  237.     avp = argv;
  238.     fvi = 0;
  239.     pvi = 0;
  240.     waitflag = 0;
  241.     userflag = NULL;
  242.     usr_ovrd[0] = 0;
  243.  
  244.     for (i = argc; --i > 0; )
  245.     {
  246.         p = *++avp;
  247.         if (p[0] == '+')
  248.         {
  249.             if (p[1] == 'w')
  250.                 waitflag = 1;
  251.             else
  252.                 goto boring;
  253.         }
  254.         else if (p[0] == '-')
  255.         {
  256.             switch (p[1])
  257.             {
  258.               case 'w':
  259.                 waitflag = -1;
  260.                 break;
  261.             
  262.               case 'u':
  263.                 if (p[2] == ':')
  264.                 {
  265.                     if (p[3] == 0 || p[4] == 0 || p[5] != 0)
  266.                     {
  267.                         printf("Bad flag %s\n", p);
  268.                         exit(-1);
  269.                     }
  270.                     smove(&p[3], usr_ovrd);
  271.                 }
  272.                 else
  273.                     userflag = &p[2];
  274.                 break;
  275.  
  276.               default:
  277.                 /* not an interesting flag */
  278.             boring:
  279.                 if (fvi >= MAXFARGS)
  280.                 {
  281.                     printf("Too many flags\n");
  282.                     exit(-1);
  283.                 }
  284.                 Flagvect[fvi++] = p;
  285.                 break;
  286.             }
  287.         }
  288.         else
  289.         {
  290.             /* not a flag: save in Parmvect */
  291.             if (pvi >= MAXPARGS)
  292.             {
  293.                 printf("Too many parmameters\n");
  294.                 exit(-1);
  295.             }
  296.             Parmvect[pvi++] = p;
  297.         }
  298.     }
  299.  
  300.     if (pvi <= 0 && dbflag)
  301.     {
  302.         return (NODBNAME);    /* no database name specified */
  303.     }
  304.  
  305.     /*
  306.     **  Scan the "users" file.
  307.     */
  308.  
  309.     if ((iop = fopen(ztack(Pathname, "/files/users"), "r")) == NULL)
  310.         syserr("initucode: open error");
  311.     
  312.     /* get uid (out of loop) for test */
  313.     actualuid = getuid();
  314.     
  315.     /* scan users file, one line at a time */
  316.     rtval = INVALIDUSR;
  317.     while ((Usercode == NULL || userflag != NULL) && fgets(buf, MAXLINE, iop) != NULL)
  318.     {
  319.     
  320.         /* decode users file entry */
  321.         i = 0;
  322.         field[0] = buf;
  323.         for (p = buf; *p != '\n' && *p != '\0'; p++)
  324.         {
  325.             if (*p == ':')
  326.             {
  327.                 *p = 0;
  328.                 i++;
  329.                 field[i] = p + 1;
  330.             }
  331.         }
  332.         *p = '\0';
  333.  
  334.         /* check for correct number of fields */
  335.         if (i != UF_NFIELDS - 1)
  336.             syserr("initucode: users fmt %s", buf);
  337.  
  338.         /*
  339.         **  Check to see if this entry is the override user.
  340.         **  If so, save his user code in usr_ovrd.
  341.         */
  342.  
  343.         if (userflag != NULL && sequal(userflag, field[UF_NAME]))
  344.         {
  345.             smove(field[UF_UCODE], usr_ovrd);
  346.             userflag = NULL;
  347.         }
  348.  
  349.         /* don't bother with this shit if not needed */
  350.         if (Usercode != NULL)
  351.             continue;
  352.         
  353.         /*
  354.         **  Build the user id of this entry into 'uid'
  355.         **  and see if it is this user.
  356.         */
  357.  
  358.         uid = atoi(field[UF_UID]);
  359.  
  360.         if (uid != actualuid)
  361.             continue;
  362.  
  363.         /*
  364.         **  We now have the real user entry.
  365.         **    Fetch the usercode, the status bits, and other
  366.         **    fields from the users file, and save them in
  367.         **    a safe place (sbuf).
  368.         */
  369.  
  370.         Usercode = sbufp;
  371.         sbufp += smove(field[UF_UCODE], sbufp) + 1;
  372.         Status = oatoi(field[UF_STAT]);
  373.         if (paramlist != NULL)
  374.         {
  375.             for (i = 0; i < 4; i++)
  376.             {
  377.                 paramlist[i] = sbufp;
  378.                 sbufp += smove(field[UF_FLAGS + i], sbufp) + 1;
  379.             }
  380.         }
  381.  
  382.         /* validate access permission */
  383.         rtval = 0;
  384.         if (!dbflag || (Status & U_SUPER) != 0)
  385.             continue;
  386.         p = field[UF_DBLIST];
  387.         if (*p == 0)
  388.             continue;
  389.  
  390.         /* select permission/no-permission */
  391.         npermit = 0;
  392.         if (*p == '-')
  393.         {
  394.             p++;
  395.             npermit++;
  396.         }
  397.  
  398.         /* scan for database listed */
  399.         if (!npermit)
  400.             rtval = NOACCESS;
  401.         for (c = *p; c != 0; p = q + 1)
  402.         {
  403.             for (q = p; *q != ',' && *q != 0; q++)
  404.                 continue;
  405.             c = *q;
  406.             *q = 0;
  407.             if (sequal(Parmvect[0], p))
  408.             {
  409.                 rtval = npermit ? NOACCESS : 0;
  410.                 break;
  411.             }
  412.         }
  413.     }
  414.     fclose(iop);
  415.  
  416.     if (rtval != 0)
  417.         return (rtval);
  418.  
  419.     /*
  420.     **  Check for existance of the database.  This is done by
  421.     **    first building the pathname of the database into
  422.     **    'Dbpath', and then reading the admin file (just
  423.     **    the adhdr part).
  424.     */
  425.  
  426.     if (dbflag)
  427.     {
  428.         Dbpath = sbufp;
  429.         switch (i = initdbpath(Parmvect[0], Dbpath, TRUE))
  430.         {
  431.           case DBEXIST:
  432.             rtval = 0;
  433.             break;
  434.  
  435.           case PTR2DB:
  436.             rtval = INDIRECT;
  437.             break;
  438.  
  439.           case NODBS:
  440.             rtval = NODB;
  441.             break;
  442.  
  443.           case PTR2NODBS:
  444.             rtval = INDNODB;
  445.             break;
  446.  
  447.           default:
  448.             syserr("initucode: initdbpath %d", i);
  449.         }
  450.         sbufp += length(Dbpath) + 1;
  451.  
  452.         if (rtval == 0 || rtval == INDIRECT)
  453.         {
  454.             i = open(ztack(Dbpath, "/admin"), O_RDONLY);
  455.             if (i < 0)
  456.                 rtval += 1;
  457.             else
  458.             {
  459.                 /* open and check admin file */
  460.                 checkadmin(i);
  461.                 close(i);
  462.             }
  463.         }
  464.     }
  465.  
  466.     /*
  467.     **  Check to see if the name on the -u flag is valid, and
  468.     **    that this user is allowed to use it.
  469.     */
  470.  
  471.     if (userflag != NULL)
  472.     {
  473.         printf("Invalid user name %s\n", userflag);
  474.         exit(-1);
  475.     }
  476.     if (usr_ovrd[0] != '\0')
  477.     {
  478.         if ((Status & U_SUPER) == 0)
  479.         {
  480.             if (!dbflag || !bequal(Admin.adhdr.adowner, Usercode, UCODE_SZ))
  481.             {
  482.                 printf("You may not use the -u flag\n");
  483.                 exit(-1);
  484.             }
  485.         }
  486.         bmove(usr_ovrd, Usercode, UCODE_SZ);
  487.     }
  488.  
  489.     /*
  490.     **  Process the +-w flag.
  491.     **    First, determine the locking mode.  If +w, always
  492.     **    wait; if -w, never wait; if unspecified, wait if in
  493.     **    background, but print error and exit if running
  494.     **    interactive.
  495.     */
  496.  
  497.     if (waitflag > 0 || (waitflag == 0 && isatty(0) == 0)) 
  498.         Wait_action = A_SLP;
  499.     else
  500.         Wait_action = A_RTN;
  501.     if (dbflag && waitmode >= 0)
  502.         db_lock(waitmode);
  503.     
  504.     /*
  505.     **  Return authorization value.
  506.     */
  507.  
  508.     return (rtval);
  509. }
  510. /*
  511. **  DB_LOCK -- lock database
  512. **
  513. **    Locks the database.  Everyone should do this before using any
  514. **    database.
  515. **
  516. **    Parameters:
  517. **        database -- the pathname of the database.
  518. **        mode -- M_EXCL -- get an exclusive lock.
  519. **            M_SHARE -- get a shared lock.
  520. **
  521. **    Returns:
  522. **        none
  523. **
  524. **    Side Effects:
  525. **        Alockdes is opened.
  526. */
  527.  
  528. struct lockreq    Lock;    /* the database lock structure */
  529.  
  530. db_lock(mode)
  531. int    mode;
  532. {
  533.     if ((Admin.adhdr.adflags & A_DBCONCUR) == 0)
  534.         return;
  535.     if (Alockdes < 0)
  536.         Alockdes = start_up_lock_driver();
  537.     if (setdbl(Wait_action, mode) < 0)
  538.     {
  539.         printf("Database temporarily unavailable\n");
  540.         exit(1);
  541.     }
  542. }
  543. /*
  544. **  INITDBPATH -- initialize the pathname of the database
  545. **
  546. **    The pathname of a specified database is created.  Indirection
  547. **    via a file is supported, so that if the pathname is a file,
  548. **    the first line of the file is read and used as the pathname
  549. **    of the real database.
  550. **
  551. **    Parameters:
  552. **        database -- the name of the database.  If NULL,
  553. **            the pathname of datadir is returned.
  554. **        dbbuf -- a buffer into which the pathname should
  555. **            be dumped.
  556. **        follow -- if set, follow the indirect chain of
  557. **            database pathnames.
  558. **
  559. **    Returns:
  560. **        0(DBEXIST)-- database exists in datadir
  561. **        1(PTR2DB)-- database exists, but I followed a pointer.
  562. **        2(NODBS)-- database doesn't exist in datadir.
  563. **        3(PRT2NODBS)-- database doesn't exist, but I followed a pointer.
  564. **
  565. **    Side Effects:
  566. **        none.
  567. */
  568.  
  569. initdbpath(database, dbpath, follow)
  570. char    *database;
  571. char    *dbpath;
  572. int    follow;
  573. {
  574.     struct stat    ibuf;
  575.     register char    *d;
  576.     register FILE    *f;
  577.     register int    phase;
  578.     int        retval;
  579.     int        uid;
  580.     extern char    *index();
  581.  
  582.     d = dbpath;
  583.  
  584.     if (database == NULL)
  585.     {
  586. # ifndef xDBPATH
  587.         concat(Pathname, "/data/base/", d);
  588. # else
  589.         smove(xDBPATH, d);
  590. # endif
  591.         return (DBEXIST);
  592.     }
  593.  
  594.     /* get the basic pathname */
  595.     concat(ztack(Pathname, "/datadir/"), database, d);
  596.  
  597.     /*
  598.     ** Iterate looking for database.
  599.     **    "Phase" is what we are trying:
  600.     **       -1 -- looking in datadir
  601.     **        0 -- looking in data/base
  602.     **        1 -- following indirect.
  603.     */
  604.  
  605.     retval = NODBS;
  606.     for (phase = -1;;)
  607.     {
  608.         /* find out what sort of filesystem node this is */
  609.         if (stat(d, &ibuf) < 0)
  610.         {
  611.             if (phase < 0)
  612.             {
  613. # ifdef xDBPATH
  614.                 concat(xDBPATH, database, d);
  615. # else
  616.                 concat(ztack(Pathname, "/data/base/"), database, d);
  617. # endif
  618.                 phase = 0;
  619.                 continue;
  620.             }
  621.             else
  622.                 return (retval);
  623.         }
  624.         
  625.         /* set up the lock structure for future use */
  626.         bmove(&ibuf, Lock.dbnode, 4);
  627.  
  628.         retval -= 2;
  629.         if ((ibuf.st_mode & S_IFMT) == S_IFDIR)
  630.             return (retval);
  631.         
  632.         /* if second time through, the database must be a directory */
  633.         if (phase > 0)
  634.             syserr("initdbpath: not direc");
  635.         
  636.         /* if we shouldn't follow the chain, say it exists */
  637.         if (!follow)
  638.             return (PTR2NODBS);
  639.         
  640.         /* it's a file -- see if we can use it */
  641.         uid = ibuf.st_uid;
  642.         if (uid != Ing_uid || (ibuf.st_mode & 0777) != 0600)
  643.             return (PTR2NODBS);
  644.         
  645.         f = fopen(d, "r");
  646.         if (f == NULL)
  647.             syserr("initdbpath: fopen");
  648.     
  649.         /* read the pathname of the database */
  650.         if (fgets(d, MAXLINE, f) == NULL || d[0] != '/')
  651.             syserr("initdbpath: bad indirect");
  652.         *index(d, '\n') = '\0';
  653.         fclose(f);
  654.  
  655.         /* prepare for next iteration */
  656.         retval = 3;
  657.         phase = 1;
  658.     }
  659. }
  660.